<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        
    </style>
</head>
<body>
    <div class="app">
        <div>我叫{{ name }}，今年{{age}}岁，性别{{sex}}，爱好{{hobby}}</div>
        <div>我叫{{name}}，今年{{age}}岁，性别{{sex}}</div>
        <div>我叫{{name}}，今年{{age}}岁，性别{{sex}}</div>
        <div>我叫{{name}}，今年{{age}}岁，性别{{sex}}</div>
    </div>
</body>
<script>
    function Vue(ops){
        // 1. 解析参数
        const {el="", data={}} = ops;
        // 2. 选择要操作的DOM元素，并获取元素内容
        const element = document.querySelector(el);
        const str = element.innerHTML;
        // 3. 初始先渲染一次页面结构
        render(element, str, data);
        // 4. 准备存储劫持之后的属性
        const target = {};
        // 5. 遍历传入的对象（被劫持的对象）
        for( let i in data ){
            // 6. 根据遍历到的属性，添加到目标对象上，并设置访问器和控制器
            Object.defineProperty(target, i, {
                get(){
                    return data[i];
                },
                set(v){
                    data[i] = v;
                    // 7. 当对象的属性发生修改时，重新渲染页面结构
                    render(element, str, data);
                }
            })
        }
        // 根据数据渲染页面的功能封装
        function render(el, str, obj){
            const arr = [];
            for(let i in obj){
                const reg = new RegExp("{{ *"+ i +" *}}", "g");
                arr.push(...str.match(reg));
            }
            arr.forEach(val=>{
                const reg = /[^{{ }}]+/;
                str = str.replace(val, obj[val.match(reg)[0]]);
            })
            el.innerHTML = str;
        }
        // 8. 返回劫持成功后的对象，以便在外部操作对象的属性
        return target;
    }
    
    const vm = new Vue({
        el:".app",
        data:{
            name:"张三",
            age:21,
            sex:"男"
        }
    })

    console.log(vm);

    vm.name = "王二";
    vm.age = 30;
    vm.hobby = "篮球";
    
</script>
</html>